/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package controller;

import exception.AccessErrorException;
import exception.CombinaisonInconnue;
import exception.ScoreAvantLancerException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import modele.*;

import modele.combinaison.As;
import modele.combinaison.Brelan;
import modele.combinaison.Carre;
import modele.combinaison.Chance;
import modele.combinaison.Cinq;
import modele.combinaison.Deux;
import modele.combinaison.Full;
import modele.combinaison.GrandeSuite;
import modele.combinaison.PetiteSuite;
import modele.combinaison.Quatre;
import modele.combinaison.Six;
import modele.combinaison.Trois;
import modele.combinaison.Yams;
import vue.VueAccueil;
import vue.VueYams;

/**
 * Classe ApplicationController : Effectue la liaison entre la vue
 * VueYams et le modèle du Yams.
 * @author Khémon Beh & Florian Minin
 */
public class ApplicationController implements ActionListener, WindowListener {

    /**
     * Attributs de la classe ApplicationController
     */
    
    private VueYams vue;
    private ModeleYamsInterface modele;
    private Map<String, String> mapCombiBouton;

    /**
     * Constructeur du controleur prenant en paramètre la vue
     * et le modèle
     * @param _vue : Vue principale
     * @param _modeleYams : Modèle du yams
     */
    public ApplicationController(VueYams _vue, ModeleYamsInterface _modeleYams) {

        vue = _vue;
        modele = _modeleYams;
        //Remplissage de la map de boutons
        initialiseCombinaisonsBoutons();
    }

    /**
     * Implémentation de la méthode actionPerformed
     * @param e <tt>ActionEvent</tt> correspondant a l'évènement provoqué
     * par le bouton sur lequel l'utilisateur (ou l'IA) a cliqué.
     */
    public void actionPerformed(ActionEvent e) {
        //On test l'ActionCommand, s'il correspond avec l'un des boutton
        //on fait le traitement adéquat
        List<Integer> l = new ArrayList<Integer>();
        Map<String, Integer> mapCombiScore = new HashMap<String, Integer>();
        int score = 0;

        //Récupération de l'actionCommand afin de déterminer
        //le bouton source.
        String ac = e.getActionCommand();

        //Boutons de choix de langue
        if (ac.equals(VueYams.BTN_FR)) {
            vue.setLangueApplication(Locale.FRANCE);
        } else if (ac.equals(VueYams.BTN_EN)) {
            vue.setLangueApplication(Locale.UK);
        } //Bouton 'lancer les dés'
        else if (ac.equals(VueYams.BTN_LANCER)) {
            if (modele.getNbLanceDesRestant() > 0) {
                l = modele.jetteDes();
                vue.afficheDes(l);
            }
        }
        //Boutons de sélection des dés
        else if (ac.equals(VueYams.BTN_DE1)) {
            selectionneDe(1, l, mapCombiScore, ac);
        } else if (ac.equals(VueYams.BTN_DE2)) {
            selectionneDe(2, l, mapCombiScore, ac);
        } else if (ac.equals(VueYams.BTN_DE3)) {
            selectionneDe(3, l, mapCombiScore, ac);
        } else if (ac.equals(VueYams.BTN_DE4)) {
            selectionneDe(4, l, mapCombiScore, ac);
        } else if (ac.equals(VueYams.BTN_DE5)) {
            selectionneDe(5, l, mapCombiScore, ac);
        }
        //Boutons de selection des combinaison
        else {
            try {
                //On met à jour la feuille de score du joueur par
                //rapport a la combinaison selectionnée par le joueur
                score = modele.enregistreScoreTour(mapCombiBouton.get(ac));
                vue.setScoreJoueur(modele.getJoueurActuel().getNumJoueur(), score);
                //On passe au joueur suivant
                AbstractJoueur joueurSuivant = modele.aQuiLeTour();
                if (joueurSuivant.getNumJoueur() == ModeleYams.CODE_JOUEUR1) {
                    //Si le joueur suivant est le joueur 1 et qu'il a terminé la partie est finie
                    if (joueurSuivant.aFiniDeJoueur()) {
                        finDePartie();
                    }
                    vue.setBoutonAJoueur(ac, VueYams.JOUEUR_2);
                    vue.auTourDe(VueYams.JOUEUR_1);
                } else {
                    vue.setBoutonAJoueur(ac, VueYams.JOUEUR_1);
                    vue.auTourDe(VueYams.JOUEUR_2);
                }

                //Remet les scores de la fenêtre a zéro
                vue.reinitialiseScores();

                String combi = "";
                //Si le joueur est doté d'une IA
                if (IA.class.isInstance(joueurSuivant)) {
                    IA ia = (IA) joueurSuivant;

                    //Le joueur joue le coup de la combinaison a jouer
                    combi = ia.jouerCoup(modele);

                    //Le joueur selectionne le dé correspondant a la
                    //combinaison qu'il doit jouer
                    for (Entry<String, String> couple : mapCombiBouton.entrySet()) {
                        if (couple.getValue().equals(combi)) {
                            //Simulation d'un clic sur la combinaison correspondante
                            actionPerformed(vue.getActionEvent(couple.getKey()));
                            break;
                        }
                    }
                }
            } catch (ScoreAvantLancerException ex) {
                vue.afficheErreurScoreAvantLancer();
            } catch (CombinaisonInconnue ex) {
                vue.afficheErreurCombiInconnu();
            }
        }
    }

    /**
     * Selectionne un dé.
     * @param numeroDe <tt>int</tt> correspondant au dé selectionné
     * @param l <tt>List<Integer></tt> Liste d'entiers permettant de récupérer la valeur
     * du dé selectionné
     * @param mapCombiScore <tt>Map<String,Integer></tt> Dictionnaire qui associe pour un
     * nom de combinaison un score.
     * @param ac <tt>String</tt> de l'actionCommand du dé selectionné.
     */
    private void selectionneDe(int numeroDe, List<Integer> l, Map<String, Integer> mapCombiScore, String ac) {
        if (modele.estDispo(numeroDe)) {
            modele.selectDe(numeroDe);
            vue.verrouilleBouton(ac);
        } else {
            if (modele.deselectDe(numeroDe)) {
                vue.deverrouilleBouton(ac);
            }
        }
        mapCombiScore = modele.calculScoreCombis();
        demandeVueAfficheScore(mapCombiScore);
    }

    /**
     * Méthode privée qui indique à la vue d'afficher les différents
     * scores pour chaque combinaison
     * @param mapDonnees Ensemble des dés selectionnés.
     */
    private void demandeVueAfficheScore(Map<String, Integer> mapDonnees) {
        vue.setTextScoreSommeUn(mapDonnees.get(As.COMBINAISON_AS).toString());
        vue.setTextScoreSommeDeux(mapDonnees.get(Deux.COMBINAISON_DEUX).toString());
        vue.setTextScoreSommeTrois(mapDonnees.get(Trois.COMBINAISON_TROIS).toString());
        vue.setTextScoreSommeQuatre(mapDonnees.get(Quatre.COMBINAISON_QUATRE).toString());
        vue.setTextScoreSommeCinq(mapDonnees.get(Cinq.COMBINAISON_CINQ).toString());
        vue.setTextScoreSommeSix(mapDonnees.get(Six.COMBINAISON_SIX).toString());
        vue.setTextScoreBrelan(mapDonnees.get(Brelan.COMBINAISON_BRELAN).toString());
        vue.setTextScoreCarre(mapDonnees.get(Carre.COMBINAISON_CARRE).toString());
        vue.setTextScoreFull(mapDonnees.get(Full.COMBINAISON_FULL).toString());
        vue.setTextScorePetiteSuite(mapDonnees.get(PetiteSuite.COMBINAISON_PETITE_SUITE).toString());
        vue.setTextScoreGrandeSuite(mapDonnees.get(GrandeSuite.COMBINAISON_GRANDE_SUITE).toString());
        vue.setTextScoreYams(mapDonnees.get(Yams.COMBINAISON_YAMS).toString());
        vue.setTextScoreChance(mapDonnees.get(Chance.COMBINAISON_CHANCE).toString());
    }

    public void windowOpened(WindowEvent e) {
    }

    /**
     * Code executé a la fermeture de la fenêtre
     * @param e <tt>WindowEvent</tt> provoquant la fermeture de la
     * fenêtre.
     */
    public void windowClosing(WindowEvent e) {

        int rep = vue.afficheDemandeQuitterPartie();
        //Si l'utilisateur a confirmé qu'il voulait quitter la partie
        if(rep == 0){
            //On revient à l'écran d'accueil
            afficheAccueil();
        }
    }

    public void windowClosed(WindowEvent e) {
//        System.exit(0);
    }

    public void windowIconified(WindowEvent e) {
    }

    public void windowDeiconified(WindowEvent e) {
    }

    public void windowActivated(WindowEvent e) {
    }

    public void windowDeactivated(WindowEvent e) {
    }

    /**
     * Initialise la map de boutons afin de pouvoir associer
     * a chaque bouton l'actionCommand de la vue correspondant.
     */
    private void initialiseCombinaisonsBoutons() {
        mapCombiBouton = new HashMap<String, String>();
        mapCombiBouton.put(VueYams.BTN_SCORE_1, As.COMBINAISON_AS);
        mapCombiBouton.put(VueYams.BTN_SCORE_2, Deux.COMBINAISON_DEUX);
        mapCombiBouton.put(VueYams.BTN_SCORE_3, Trois.COMBINAISON_TROIS);
        mapCombiBouton.put(VueYams.BTN_SCORE_4, Quatre.COMBINAISON_QUATRE);
        mapCombiBouton.put(VueYams.BTN_SCORE_5, Cinq.COMBINAISON_CINQ);
        mapCombiBouton.put(VueYams.BTN_SCORE_6, Six.COMBINAISON_SIX);
        mapCombiBouton.put(VueYams.BTN_SCORE_BRELAN, Brelan.COMBINAISON_BRELAN);
        mapCombiBouton.put(VueYams.BTN_SCORE_CARRE, Carre.COMBINAISON_CARRE);
        mapCombiBouton.put(VueYams.BTN_SCORE_PSUITE, PetiteSuite.COMBINAISON_PETITE_SUITE);
        mapCombiBouton.put(VueYams.BTN_SCORE_GSUITE, GrandeSuite.COMBINAISON_GRANDE_SUITE);
        mapCombiBouton.put(VueYams.BTN_SCORE_FULL, Full.COMBINAISON_FULL);
        mapCombiBouton.put(VueYams.BTN_SCORE_CHANCE, Chance.COMBINAISON_CHANCE);
        mapCombiBouton.put(VueYams.BTN_SCORE_YAMS, Yams.COMBINAISON_YAMS);
    }

    /**
     * Met fin a la partie en affichant le gagnant.
     */
    private void finDePartie() {
        AbstractJoueur gagnant = modele.getLeader();
        int joueurVue = 0;
        int score = 0;
        if (gagnant != null) {
            if (gagnant.getNumJoueur() == ModeleYams.CODE_JOUEUR1) {
                joueurVue = VueYams.JOUEUR_1;
             
            } else if (gagnant.getNumJoueur() == ModeleYams.CODE_JOUEUR2) {
                joueurVue = VueYams.JOUEUR_2;
            }
            try {
                        //On enregistre le score du gagnant dans le palmares
                PalmaresBDD.ajouterScoreBDD(new EnregistrementScore(gagnant.getNom(), gagnant.getScore()));
            } catch (AccessErrorException ex) {
                System.out.println("Insertion impossible");
            }

        }
        vue.afficheFinDePartie(joueurVue);
        //redirection de l'utilisateur vers l'accueil
        afficheAccueil();
    }

    /**
     * Méthode privée qui permet de retourner à l'accueil lors de la fermeture
     * de la vue
     */
    private void afficheAccueil(){
        //On crée une nouvelle vue d'accueil en prenant la locale en cours
        //comme langue de référence
        vue.dispose();

        VueAccueil vueAccueil = new VueAccueil(vue.getLocale());
        ControllerAccueil ctrl = new ControllerAccueil(vueAccueil, modele);
        vueAccueil.abonneComposants(ctrl);
        vueAccueil.setVisible(true);
    }
}
